package org.zn.note.spring.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;
import org.zn.note.spring.dao.jdbc.IngredientRepository;
import org.zn.note.spring.dao.jdbc.TacoRepository;
import org.zn.note.spring.dao.jpa.IngredientJpaRepository;
import org.zn.note.spring.domain.Ingredient;
import org.zn.note.spring.domain.Ingredient.Type;
import org.zn.note.spring.domain.Order;
import org.zn.note.spring.domain.Taco;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 构建taco(墨西哥卷饼)配料列表
 */
@Slf4j // = private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DesignTacoController.class);
@Controller
@RequestMapping("/design")
// 作用在Controller上，可以将Model中的属性同步到session中
// 正常Model作用域是request，可以指定属性用于session
@SessionAttributes("order")
public class DesignTacoController {

    private final IngredientRepository ingredientRepository;
    private final TacoRepository tacoRepository;

    // 试一下JPA
    private final IngredientJpaRepository ingredientJpaRepository;

    @Autowired
    public DesignTacoController(
            IngredientRepository ingredientRepository,
            TacoRepository tacoRepository,
            IngredientJpaRepository ingredientJpaRepository
    ) {
        this.ingredientRepository = ingredientRepository;
        this.tacoRepository = tacoRepository;
        this.ingredientJpaRepository = ingredientJpaRepository;
    }

    /*
    @ModelAttribute 两种用法
    1、加在参数上：表示从Model中取数据，注入到这个参数上
    public String processDesign(..., @ModelAttribute Order order)
    public String processDesign(..., @ModelAttribute("order") Order order)
    如果不加这个，就是从请求参数中取；加了这个就不从请求参数了，从Model中取
    2、加在方法上：创建一个对象，放到Model中（确保Model有这样一个对象）
    如下面例子
     */
    @ModelAttribute(name = "order")
    public Order order() {
        return new Order();
    }

    @ModelAttribute(name = "taco")
    public Taco taco() {
        return new Taco();
    }

    @GetMapping // = @RequestMapping(method=RequestMethod.GET)
    // Model负责在Controller和View之间传递数据
    // Thymeleaf是模板引擎，它并不知道spring的存在；同样Spring也不关心前端的显示用的什么框架
    // Spring只管把Model放到Servlet Request中；前端只管从Servlet Request里面取
    public String showDesignForm(Model model) {
        // 从数据源获取配料列表
//        List<Ingredient> ingredients = loadLocalIngredients(); // 本地静态数据
        List<Ingredient> ingredients = new ArrayList<>();
        ingredientRepository.findAll().forEach(i -> ingredients.add(i)); // jdbc
//        ingredientJpaRepository.findAll().forEach(i -> ingredients.add(i)); // jpa
        // 按类型分组

        for (Type type : Ingredient.Type.values()) {
            model.addAttribute(type.toString().toLowerCase(), filterByType(ingredients, type));
        }
        model.addAttribute("design", new Taco());
        return "design";
    }

    // html中form仅指定了method=post，没有指定action，则表单提交到当前页面的url
    @PostMapping
    public String processDesign(
            @Valid Taco design,
            Errors errors,
            @ModelAttribute Order order) {
        if (errors.hasErrors())
            return "design";
        Taco saved = tacoRepository.save(design);
        order.addDesign(saved);
        log.info("Process design: {}", design);
        // 重定向：server 发送应答码 3xx + 重定向地址，然后浏览器会做二次请求，地址栏也会变
        // 这里是Taco(配料搭配好了)创建好后，要去创建订单了
        return "redirect:/orders/current";
    }

    // 将配料列表，根据Type分类
    private List<Ingredient> filterByType(List<Ingredient> ingredients, Type type) {
        return ingredients.stream()
                .filter(x -> x.getType().equals(type))
                .collect(Collectors.toList());
    }

    // 本地数据源，模仿数据库返回的数据
    private List<Ingredient> loadLocalIngredients() {
        return Arrays.asList(
                new Ingredient("FLTO", "Flour Tortilla", Type.WRAP),
                new Ingredient("COTO", "Corn Tortilla", Type.WRAP),
                new Ingredient("GRBF", "Ground Beef", Type.PROTEIN),
                new Ingredient("CARN", "Carnitas", Type.PROTEIN),
                new Ingredient("TMTO", "Diced Tomatoes", Type.VEGGIES),
                new Ingredient("LETC", "Lettuce", Type.VEGGIES),
                new Ingredient("CHED", "Cheddar", Type.CHEESE),
                new Ingredient("JACK", "Monterrey Jack", Type.CHEESE),
                new Ingredient("SLSA", "Salsa", Type.SAUCE),
                new Ingredient("SRCR", "Sour Cream", Type.SAUCE));
    }
}
